﻿/*
 * DotNetCrypt - an open source library of cryptographic algorithms for .NET
 * Copyright (C) 2009 David Musgrove
 * 
 * This file is part of DotNetCrypt.
 *
 * DotNetCrypt is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * DotNetCrypt is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

using System;
using System.Security.Cryptography;

namespace DotNetCrypt
{
    /// <summary>
    /// Accesses the managed version of the <see cref="DES" /> algorithm.
    /// This class cannot be inherited.
    /// </summary>
// ReSharper disable InconsistentNaming
    public sealed class DESManaged : DES, ISymmetricAlgorithm
// ReSharper restore InconsistentNaming
    {
        /// <summary>
        /// Creates a symmetric encryptor object with the specified
        /// <see cref="P:System.Security.Cryptography.SymmetricAlgorithm.Key"/>
        /// property and initialization vector
        /// (<see cref="P:System.Security.Cryptography.SymmetricAlgorithm.IV"/>).
        /// </summary>
        /// <returns>
        /// A symmetric encryptor object.
        /// </returns>
        /// <param name="rgbKey">
        /// The secret key to use for the symmetric algorithm.
        /// </param>
        /// <param name="rgbIV">
        /// The initialization vector to use for the symmetric algorithm.
        /// </param>
// ReSharper disable InconsistentNaming
        public override ICryptoTransform CreateEncryptor(byte[] rgbKey, byte[] rgbIV)
// ReSharper restore InconsistentNaming
        {
            return Utils.NewEncryptor(this, typeof(DESManagedTransform), rgbKey, ExtendedMode, rgbIV, TransformDirection.Encrypt);
        }

        /// <summary>
        /// Creates a symmetric decryptor object with the specified
        /// <see cref="P:System.Security.Cryptography.SymmetricAlgorithm.Key"/>
        /// property and initialization vector
        /// (<see cref="P:System.Security.Cryptography.SymmetricAlgorithm.IV"/>).
        /// </summary>
        /// <returns>
        /// A symmetric decryptor object.
        /// </returns>
        /// <param name="rgbKey">
        /// The secret key to use for the symmetric algorithm.
        /// </param>
        /// <param name="rgbIV">
        /// The initialization vector to use for the symmetric algorithm.
        /// </param>
// ReSharper disable InconsistentNaming
        public override ICryptoTransform CreateDecryptor(byte[] rgbKey, byte[] rgbIV)
// ReSharper restore InconsistentNaming
        {
            return Utils.NewEncryptor(this, typeof(DESManagedTransform), rgbKey, ExtendedMode, rgbIV, TransformDirection.Decrypt);
        }

        /// <summary>
        /// Generates a random key
        /// (<see cref="P:System.Security.Cryptography.SymmetricAlgorithm.Key"/>)
        /// to use for the algorithm.
        /// </summary>
        public override void GenerateKey()
        {
            KeyValue = new byte[KeySizeValue >> 3];
            do
            {
                Utils.RandomNumberGeneratorSingleton.GetBytes(KeyValue);
            } while (IsWeakKey(KeyValue));
        }

        /// <summary>
        /// Generates a random initialization vector
        /// (<see cref="P:System.Security.Cryptography.SymmetricAlgorithm.IV"/>)
        /// to use for the algorithm.
        /// </summary>
        public override void GenerateIV()
        {
            IVValue = new byte[BlockSizeValue / 8];
            Utils.RandomNumberGeneratorSingleton.GetBytes(IVValue);
        }

        /// <summary>
        /// Gets or sets the block cipher chaining mode to be used by this
        /// instance of the algorithm.
        /// </summary>
        /// <remarks>
        /// If compatible, this property's setter also sets the underlying
        /// <see cref="SymmetricAlgorithm.Mode" /> property, which is of the
        /// more restrictive type <see cref="CipherMode" />.
        /// </remarks>
        public ExtendedCipherMode ExtendedMode { get; set; }

        /// <summary>
        /// Gets or sets the method used to combine the counter value with the
        /// nonce in counter (<see cref="ExtendedCipherMode.CTR" />) mode.
        /// </summary>
        public NonceCombinationMode NonceCombinationMode { get; set; }

        /// <summary>
        /// Gets or sets the number of bytes to process at a time in cipher or
        /// output feedback (<see cref="ExtendedCipherMode.CFB" /> or
        /// <see cref="ExtendedCipherMode.OFB" />) modes.
        /// </summary>
        /// <remarks>
        /// If not set, this value will default to 1 byte, which provides
        /// compatibility with the CSP and .NET implementations of the
        /// modes.
        /// </remarks>
        public int RegisterShiftSize { get; set; }

        /// <summary>
        /// Returns a random non-weak key
        /// (<see cref="P:System.Security.Cryptography.SymmetricAlgorithm.Key"/>)
        /// to use for the algorithm.
        /// </summary>
        /// <returns></returns>
        public byte[] GenerateNonWeakKey()
        {
            byte[] oldKey = KeyValue;
            GenerateKey();
            byte[] newKey = Key;
            KeyValue = oldKey;
            return newKey;
        }
    }
}
